package com.ipzoe.web.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.QrCodeKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import com.ipzoe.common.core.domain.AjaxResult;
import com.ipzoe.common.utils.sign.Base64;
import com.ipzoe.common.utils.spring.SpringContextHolder;
import com.ipzoe.framework.controller.AbstractWxPayApiController;
import com.ipzoe.mem.domain.Member;
import com.ipzoe.mem.domain.MemberRechargePackage;
import com.ipzoe.mem.service.IMemberRechargePackageService;
import com.ipzoe.oms.domain.Order;
import com.ipzoe.oms.service.IOrderService;
import com.ipzoe.web.core.config.pay.WxPayProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Controller
@RequestMapping("/api/v1/wxPay")
public class WxPayController extends AbstractWxPayApiController {

    @Autowired
    WxPayProperties wxPayProperties;

    @Autowired
    private IOrderService iOrderService;

    @Autowired
    private IMemberRechargePackageService iMemberRechargePackageService;

    private String notifyUrl;
    private String refundNotifyUrl;
    private static final String USER_PAYING = "USERPAYING";

    @Override
    public WxPayApiConfig getApiConfig() {
        WxPayApiConfig apiConfig;

        try {
            apiConfig = WxPayApiConfigKit.getApiConfig(wxPayProperties.getAppId());
        } catch (Exception e) {
            apiConfig = WxPayApiConfig.builder()
                    .appId(wxPayProperties.getAppId())
                    .mchId(wxPayProperties.getMchId())
                    .partnerKey(wxPayProperties.getPartnerKey())
//                    .certPath(wxPayProperties.getCertPath())
                    .domain(wxPayProperties.getDomain())
                    .build();
        }
        notifyUrl = apiConfig.getDomain().concat("/api/v1//wxPay/payNotify");
        refundNotifyUrl = apiConfig.getDomain().concat("/api/v1/wxPay/refundNotify");
        return apiConfig;
    }

    @GetMapping("/getKey")
    @ResponseBody
    public String getKey() {
        return WxPayApi.getSignKey(wxPayProperties.getMchId(), wxPayProperties.getPartnerKey(), SignType.MD5);
    }

    /**
     * 扫码支付模式二
     */
    @RequestMapping(value = "/scanCode2", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public AjaxResult scanCode2(HttpServletRequest request, HttpServletResponse response,
                                    @RequestParam("packageId") Long packageId) throws IOException {

        if (packageId==null) {
            return AjaxResult.error(400,"未选择购买的套餐");
        }

        //获取当前登录的会员
        Member member = (Member) request.getAttribute("member");
        //查询该账户下是否存在待支付的该套餐的订单
//        LambdaQueryWrapper<Order> orderLqw = new LambdaQueryWrapper<>();
//        orderLqw.eq(Order::getMemberId, member.getId())
//                .eq(Order::getPackageId, packageId)
//                .eq(Order::getPayType,1)
//                .eq(Order::getStatus,0);
//        Order order = iOrderService.getOne(orderLqw);
//
//        if(order != null){
//            return AjaxResult.success(order.getPayImgName());
//        }
        String orderNo = iOrderService.generateOrderSn();

        MemberRechargePackage rechargePackage = iMemberRechargePackageService.getById(packageId);
        if(rechargePackage == null){
            return AjaxResult.error(400,"未选择购买的套餐");
        }

        String activeProfile = SpringContextHolder.getApplicationContext().getEnvironment().getActiveProfiles()[0];
        //单位分
        String totalFee = "1";
        if ("prod".equals(activeProfile)) {
            totalFee = String.valueOf(rechargePackage.getPrice() * 100);
        }else{
            totalFee = "1";
        }

        String ip = IpKit.getRealIp(request);
        if (StrUtil.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();

        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body("dan潜水-会员充值")
                .attach(Order.toPayParam(orderNo
                        ,String.valueOf(rechargePackage.getPrice())
                        , rechargePackage.getId()
                        , member.getId()
                        , 1,"wx_pc"))
                .out_trade_no(orderNo)
                .total_fee(totalFee)
                .spbill_create_ip(ip)
                .notify_url(notifyUrl)
                .trade_type(TradeType.NATIVE.getTradeType())
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

        log.info("微信统一下单req:" + JSON.toJSONString(params));
        String xmlResult = WxPayApi.pushOrder(false, params);
        log.info("微信统一下单res:" + xmlResult);

        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");

        if (!WxPayKit.codeIsOk(returnCode)) {
            return AjaxResult.error("error:" + returnMsg);
        }
        String resultCode = result.get("result_code");
        if (!WxPayKit.codeIsOk(resultCode)) {
            return AjaxResult.error("error:" + returnMsg);
        }
        //生成预付订单success

        String qrCodeUrl = result.get("code_url");
        String name = "WXQR_"+orderNo+".png";

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
           QrCodeKit.encodeOutPutSteam(stream,qrCodeUrl, BarcodeFormat.QR_CODE, 0, ErrorCorrectionLevel.H,"png", 200, 200);
            AjaxResult ajax = AjaxResult.success();
            ajax.put("img", Base64.encode(stream.toByteArray()));
            return ajax;
        } catch (IOException e) {
            log.error("微信支付生成二维码错误",e);
        }
        finally {
            stream.close();
        }
        return null;
    }

    /**
     * 异步通知
     */
    @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String payNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        log.info("微信支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");

        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息
                String orderNo = params.get("out_trade_no");
                String attach = params.get("attach");
                try{
                    iOrderService.payReturn(attach, "SUCCESS".equalsIgnoreCase(params.get("result_code")), JSON.toJSONString(params));
                    // 发送通知等
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }catch(Exception e){
                    log.error("支付通知发送错误",e);
                    // 发送通知等
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "FAIL");
                    xml.put("return_msg", "ERROR");
                    return WxPayKit.toXml(xml);
                }
            }
        }
        return null;
    }


}
